﻿using MDT.LifeSewagePlatform.Conmmon;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

/*********************************************************
 * 命名空间 MDT.LifeSewagePlatform.Extension
 * 接口名称 JTokenMappingEntityService
 * 开发人员：-nhy
 * 创建时间：2022/4/7 17:35:10
 * 描述说明：
 * 更改历史：
 * 
 * *******************************************************/
namespace MDT.LifeSewagePlatform.Extension
{
    public class JTokenMappingEntityService:IJTokenMappingEntityService
    {
        /// <summary>
        /// 
        /// </summary>
        public JTokenMappingEntityService()
        {

        }

        #region method
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobject"></param>
        /// <returns></returns>
        public async Task<List<T>> GetEntitys<T>(JObject jobject)
        {
            return await Task.Run(async () =>
            {
                Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
                Type tEntity = typeof(T);
                string ClassName = tEntity.GetClassName();

                foreach (var prop in tEntity.GetProperties())
                {
                    props.Add(prop.GetColName(), prop);
                }
                if (jobject[ClassName] == null || string.IsNullOrEmpty(jobject[ClassName].ToString()))
                {
                    return null;
                }
                List<T> tList = new List<T>();
                foreach (var item in jobject[ClassName].ToArray())
                {
                    T t = (T)Activator.CreateInstance(tEntity);
                    await Mapping(t, props, item, tEntity);
                    tList.Add(t);
                }
                return tList;
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobject"></param>
        /// <returns></returns>
        public async Task<T> GetEntity<T>(JObject jobject) where T : class
        {
            return await Task.Run(async () =>
            {
                Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
                Type tEntity = typeof(T);
                string ClassName = tEntity.GetClassName();

                foreach (var prop in tEntity.GetProperties())
                {
                    props.Add(prop.GetColName(), prop);
                }
                if (jobject[ClassName] == null || string.IsNullOrEmpty(jobject[ClassName].ToString()))
                {
                    return null;
                }
                JToken item = jobject[ClassName];
                T t = (T)Activator.CreateInstance(tEntity);
                await Mapping(t, props, item, tEntity);
                return t;
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jToken"></param>
        /// <returns></returns>
        public async Task<T> GetEntity<T>(JToken jToken) where T : class
        {
            return await Task.Run(async () =>
            {
                Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
                Type tEntity = typeof(T);
                T t = (T)Activator.CreateInstance(tEntity);
                string ClassName = tEntity.GetClassName();

                foreach (var prop in tEntity.GetProperties())
                {
                    props.Add(prop.GetColName(), prop);
                }
                await Mapping(t, props, jToken, tEntity);
                return t;
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="jobject"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private async Task<List<object>> GetObjects(JToken jobject, string typeName)
        {
            return await Task.Run(async () =>
            {

                Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
                Type tEntity = Type.GetType(typeName);

                foreach (var prop in tEntity.GetProperties())
                {
                    props.Add(prop.GetColName(), prop);
                }
                if (jobject == null)
                {
                    throw new Exception("error 无法通过实体中类名获取到数据!");
                }
                if (jobject.ToArray().Any() == false)
                {
                    return null;
                }
                List<object> tList = new List<object>();
                foreach (var item in jobject.ToArray())
                {
                    object t = Activator.CreateInstance(tEntity);
                    await Mapping(t, props, item, tEntity);
                    tList.Add(t);
                }
                return tList;
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="jobject"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        private async Task<object> GetObject(JToken jobject, string typeName)
        {
            return await Task.Run(async () =>
            {
                Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
                Type tEntity = Type.GetType(typeName);

                foreach (var prop in tEntity.GetProperties())
                {
                    props.Add(prop.GetColName(), prop);
                }
                if (jobject == null || string.IsNullOrEmpty(jobject.ToString()))
                {
                    return null;
                }

                JToken item = jobject;
                object obj = Activator.CreateInstance(tEntity);
                await Mapping(obj, props, item, tEntity);
                return obj;
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="props"></param>
        /// <param name="item"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private async Task Mapping(object obj, Dictionary<string, PropertyInfo> props, JToken item, Type type)
        {

            await Task.Run(async () =>
            {
                foreach (var prop in props)
                {
                    if (item[prop.Key] != null)
                    {
                        if (prop.Value.PropertyType.IsValueType || prop.Value.PropertyType == typeof(string))
                        {
                            if (prop.Value.PropertyType == typeof(string))
                            {
                                prop.Value.SetValue(obj, item[prop.Key].ToString());
                            }
                            else if (prop.Value.PropertyType == typeof(int))
                            {
                                int val = 0;
                                int.TryParse(item[prop.Key].ToString(), out val);
                                prop.Value.SetValue(obj, val);
                            }
                            else if (prop.Value.PropertyType == typeof(double))
                            {
                                double val = 0;
                                double.TryParse(item[prop.Key].ToString(), out val);
                                prop.Value.SetValue(obj, val);
                            }
                            else if (prop.Value.PropertyType == typeof(float))
                            {
                                float val = 0;
                                float.TryParse(item[prop.Key].ToString(), out val);
                                prop.Value.SetValue(obj, val);
                            }
                            else if (prop.Value.PropertyType == typeof(long))
                            {
                                long val = 0;
                                long.TryParse(item[prop.Key].ToString(), out val);
                                prop.Value.SetValue(obj, val);
                            }
                            else if (prop.Value.PropertyType == typeof(DateTime))
                            {
                                DateTime val = DateTime.Now;
                                DateTime.TryParse(item[prop.Key].ToString(), out val);
                                prop.Value.SetValue(obj, val);
                            }

                        }
                        else
                        {
                            MethodInfo[] methodinfos = type.GetMethods().Where(t => t.Name.Contains("Convert")).ToArray();
                            string typeName = prop.Value.ToString();
                            //System.Collections.Generic.List`[]动态创建list集合
                            if (typeName.Contains(typeof(List<>).ToString().Split('`')[0]))
                            {
                                int start = typeName.IndexOf("[") + 1;
                                int length = typeName.IndexOf("]") - start;

                                string childTypeName = typeName.Substring(start, length);
                                string PropName = prop.Value.GetColName();

                                MethodInfo meConvertList = null;

                                if (methodinfos != null)
                                {
                                    meConvertList = methodinfos.Where(t => t.Name.Contains(PropName)).FirstOrDefault();
                                }
                                if (meConvertList == null)
                                {
                                    prop.Value.SetValue(obj, meConvertList.Invoke(obj, new object[] { null }));
                                }
                                else
                                {
                                    prop.Value.SetValue(obj, meConvertList.Invoke(obj, new object[] { await GetObjects(item[PropName], childTypeName) }));
                                }
                            }
                            else
                            {
                                string childTypeName = prop.Value.PropertyType.ToString();
                                prop.Value.SetValue(obj, await GetObject(item[prop.Value.GetColName()], childTypeName));
                            }
                        }
                    }
                }
            });
        }
        #endregion
    }
}
